package com.smart.common.utils.modbus;

import com.smart.common.utils.StringUtils;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

public class ModbusUtil {
    public static Modbus analysis(String hex){
        String[] split = StringUtils.split(hex, "=");
        byte[] modbusRTUMessage = hexStringToByteArray(split[1]);
        Modbus modbus = parseModbusRTU(modbusRTUMessage);
        modbus.setKey(split[0]);
        return modbus;
    }
    public static byte[] hexStringToByteArray(String hex) {
        int len = hex.length();
        if (len % 2 != 0) {
            throw new IllegalArgumentException("Hex string must have an even number of characters");
        }
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
                    + Character.digit(hex.charAt(i+1), 16));
        }
        return data;
    }

    public static Modbus parseModbusRTU(byte[] message) {
        Modbus modbus = new Modbus();
        if (message.length < 5) {
            System.out.println("报文长度不足");
            return null;
        }

        // 子站地址
        int slaveAddress = message[0] & 0xFF;
        modbus.setSlaveAddress(slaveAddress);
//        System.out.println("子站地址: " + slaveAddress);

        // 功能码
        int functionCode = message[1] & 0xFF;
        modbus.setFunctionCode(functionCode);
//        System.out.println("功能码: " + functionCode);

        // 字节数
        int byteCount = message[2] & 0xFF;
        modbus.setByteCount(byteCount);
//        System.out.println("字节数: " + byteCount);

        // 数据域
        if (message.length < 3 + byteCount + 2) {
            System.out.println("数据域长度不足");
            return null;
        }
        byte[] dataField = new byte[byteCount];
        System.arraycopy(message, 3, dataField, 0, byteCount);
        int dataValue = ((dataField[0] & 0xFF) << 8) | (dataField[1] & 0xFF);
//        System.out.println("数据域 (十进制): " + dataValue);
        modbus.setDataValue(dataValue);

        // CRC 校验码
        int crcReceived = ((message[message.length - 2] & 0xFF) << 8) | (message[message.length - 1] & 0xFF);
        int crcCalculated = calculateCRC(message, message.length - 2);
//        System.out.println("接收到的 CRC 校验码: " + String.format("%04X", crcReceived));
        modbus.setCrcReceived(String.valueOf(crcReceived));
        modbus.setCrcCalculated(String.valueOf(crcCalculated));
//        System.out.println("计算出的 CRC 校验码: " + String.format("%04X", crcCalculated));

//        if (crcReceived == crcCalculated) {
//            System.out.println("CRC 校验通过");
//        } else {
//            System.out.println("CRC 校验失败");
//        }
        modbus.setCrcValid(crcReceived == crcCalculated);
        return modbus;
    }

    public static int calculateCRC(byte[] data, int length) {
        int crc = 0xFFFF;
        for (int i = 0; i < length; i++) {
            crc ^= (data[i] & 0xFF);
            for (int j = 0; j < 8; j++) {
                if ((crc & 0x0001) != 0) {
                    crc >>= 1;
                    crc ^= 0xA001;
                } else {
                    crc >>= 1;
                }
            }
        }
        // 确保 CRC 校验码以大端序存储
        return ((crc >> 8) & 0xFF) | ((crc & 0xFF) << 8);
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @ToString
    public static class Modbus{
        @Schema(name = "键")
        private String key;

        @Schema(name = "子站地址")
        private int slaveAddress;

        @Schema(name = "功能码")
        private int functionCode;

        @Schema(name = "字节数")
        private int byteCount;

        @Schema(name = "数据域 (十进制)")
        private int dataValue;

        @Schema(name = "接收到的 CRC 校验码")
        private String crcReceived;

        @Schema(name = "计算出的 CRC 校验码")
        private String crcCalculated;

        @Schema(name = "CRC 校验结果")
        private boolean crcValid;
    }
}

